package com.by.hellosecurityoauth2.service.impl;

import com.by.hellosecurityoauth2.controller.request.RoleRequestBean;
import com.by.hellosecurityoauth2.controller.request.UserRoleRequestBean;
import com.by.hellosecurityoauth2.domain.*;
import com.by.hellosecurityoauth2.domain.repository.TUserRepository;
import com.by.hellosecurityoauth2.domain.repository.TUserRoleRepository;
import com.by.hellosecurityoauth2.service.UserService;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.EntityManager;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.ArrayList;
import java.util.List;

/**
 * @author 白羽
 * @Date 2022-12-03 21:26:01
 */
@Service
@Transactional(value = "transactionManager", isolation = Isolation.REPEATABLE_READ,
        propagation = Propagation.REQUIRED)
public class UserServiceImpl implements UserService {

    private final EntityManager entityManager;

    private final TUserRepository userRepository;
    private final TUserRoleRepository userRoleRepository;
    
    public UserServiceImpl(EntityManager entityManager, TUserRepository userRepository, TUserRoleRepository userRoleRepository) {
        this.entityManager = entityManager;
        this.userRepository = userRepository;
        this.userRoleRepository = userRoleRepository;
    }

    /**
     * 查询多条数据
     *
     * @param page 查询起始位置
     * @param limit 查询条数
     * @return 对象列表
     */
    @Override 
    public Page<TUser> list(int page, int limit) {
        Pageable pageable = PageRequest.of(page, limit, Sort.by(Sort.Direction.DESC, TUser_.id.getName()));
        return userRepository.findAll(pageable);
    }

    @Override
    public TUser findByUsername(String username) {
        return userRepository.findByUsername(username);
    }

    @Override
    public TUser findById(Long id) {
        return userRepository.findById(id).orElse(null);
    }

    @Override
    public TUser create(RoleRequestBean bean) {
        TUser user = new TUser();
        BeanUtils.copyProperties(bean, user);
        return userRepository.save(user);
    }

    @Override
    public TUser updateById(Long id, RoleRequestBean bean) {
        TUser user = findById(id);
        BeanUtils.copyProperties(bean, user);
        return userRepository.save(user);
    }

    @Override
    public void deleteById(Long id) {
        userRepository.deleteById(id);
    }

    @Override
    public List<TUserRole> updateUserRole(Long id, List<UserRoleRequestBean> bean) {
        userRoleRepository.deleteByUserId(id);
        List<TUserRole> userRoles = new ArrayList<>();
        for (UserRoleRequestBean role :
                bean) {
            TUserRole userRole = new TUserRole();
            BeanUtils.copyProperties(role, userRole);
            userRole.setUserId(id);
            userRoles.add(userRole);
        }
        return userRoleRepository.saveAll(userRoles);
    }

    @Override
    public List<TAuthority> getUserAuthorities(TUser user) {
        List<TUserRole> userRoles = userRoleRepository.findByUserId(user.getId());
        List<Long> roleIds = new ArrayList<>();
        for (TUserRole userRole :
                userRoles) {
            roleIds.add(userRole.getRoleId());
        }

        CriteriaBuilder cb = entityManager.getCriteriaBuilder();
        CriteriaQuery<TAuthority> cq = cb.createQuery(TAuthority.class);
        Root<TRoleAuthority> root = cq.from(TRoleAuthority.class);
        Predicate predicate = cb.conjunction();
        predicate.getExpressions().add(root.get(TRoleAuthority_.roleId).in(roleIds));
        cq.where(predicate);
        cq.select(root.get(TRoleAuthority_.authority));
        cq.distinct(true);
        return entityManager.createQuery(cq).getResultList();
    }

    @Override
    public List<TUserRole> getUserRoleByUserId(Long id) {
        return userRoleRepository.findByUserId(id);
    }


}